<?php

class Node extends CActiveRecord {
    /**
     * The followings are the available columns in table 'www_nodes':
     */

    /**
     * Returns the static model of the specified AR class.
     * @return CActiveRecord the static model class
     */
    public static function model($className=__CLASS__) {
        return parent::model($className);
    }

    /**
     * @return string the associated database table name
     */
    public function tableName() {
        return '{{nodes}}';
    }

    /**
     * @return array validation rules for model attributes.
     */
    public function rules() {
    // NOTE: you should only define rules for those attributes that
    // will receive user inputs.
        return array(
            array('name, parent_id, type, order_pos, open_target', 'required'),
            array('parent_id, order_pos, show_in_menus', 'numerical', 'integerOnly' => true),
            array('show_in_menus', 'boolean', 'trueValue' => 1, 'falseValue' => 0),
            array('url_args_frontend', 'length', 'max' => 100),
            array('open_target', 'length', 'max' => 10),
            array('name', 'length', 'max' => 200),
        );
    }

    /**
     * @return array relational rules.
     */
    public function relations() {
    // NOTE: you may need to adjust the relation name and the related
    // class name for the relations automatically generated below.
        return array(
            'article' => array(self::HAS_ONE, 'Article', 'node_id'),
        );
    }

    /**
     * @return array customized attribute labels (name=>label)
     */
    public function attributeLabels() {
        return array(
            'node_id' => Yii::t('common', 'node_id'),
            'order_pos' => Yii::t('common', 'order_pos'),
            'name' => Yii::t('node', 'name'),
            'parent_id' => Yii::t('node', 'parent_id'),
            'type' => Yii::t('node', 'type'),
            'url_args_frontend' => Yii::t('node', 'url_args_frontend'),
            'show_in_menus' => Yii::t('node', 'show_in_menus'),
            'open_target' => Yii::t('node', 'open_target'),
        );
    }

    const TYPE_ARTICLE = 'Article';
    const TYPE_POST = 'Post';
    const TYPE_LINK = 'Link';
    const TYPE_FEEDBACK = 'Feedback';
    const TYPE_DOWNLOAD = 'Download';
    const TYPE_PRODUCT = 'Product';
    const TYPE_PERSONNEL = 'Personnel';
    const TYPE_VIDEO = 'Video';
    const TYPE_MUSIC = 'Music';
    const TYPE_USER_CASE = 'UserCase';
    const TYPE_SLIDE = 'Slide';
    const TYPE_BOOK = 'Book';
    const TYPE_ALBUM = 'Album';
    const TYPE_TODAY_ON_HISTORY = 'TodayOnHistory';
    const TYPE_JOB = 'Job';

    // 节点类型
    public function getTypeOptions() {
        return array(
            self::TYPE_ARTICLE          => Yii::t('node', 'type_article'),
            self::TYPE_POST             => Yii::t('node', 'type_post'),
            self::TYPE_LINK             => Yii::t('node', 'type_link'),
            self::TYPE_FEEDBACK         => Yii::t('node', 'type_feedback'),
            self::TYPE_DOWNLOAD         => Yii::t('node', 'type_download'),
            self::TYPE_PRODUCT          => Yii::t('node', 'type_product'),
            self::TYPE_PERSONNEL        => Yii::t('node', 'type_personnel'),
            self::TYPE_VIDEO            => Yii::t('node', 'type_video'),
            self::TYPE_MUSIC            => Yii::t('node', 'type_music'),
            self::TYPE_USER_CASE        => Yii::t('node', 'type_user_case'),
            self::TYPE_SLIDE            => Yii::t('node', 'type_slide'),
            self::TYPE_BOOK             => Yii::t('node', 'type_book'),
            self::TYPE_ALBUM            => Yii::t('node', 'type_album'),
            self::TYPE_TODAY_ON_HISTORY => Yii::t('node', 'type_today_on_history'),
            self::TYPE_JOB              => Yii::t('node', 'type_job'),
        );
    }

    // 有效节点类型（屏蔽的节点模块将不会显示）
    public function getValidateTypeOptions() {
        $options = $this->typeOptions;
        $config = Yii::app()->params['nodeModule'];
        if (is_array($config)) {
            foreach ($options as $key => $value) {
                if (isset($config[$key])) {
                    if (!intval($config[$key])) {
                        unset($options[$key]);
                    }
                }
            }
        }
        return $options;
    }

    // 打开方式
    const OPEN_TARGET_SELF = '_self';
    const OPEN_TARGET_BLANK = '_blank';
    public function getOpenTargetOptions() {
        return array(
            self::OPEN_TARGET_SELF => Yii::t('node', 'open_target_self'),
            self::OPEN_TARGET_BLANK=> Yii::t('node', 'open_target_blank'),
        );
    }

    // 排序值
    public function getOrderPosOptions() {
        $order = array();
        for ($i = 1; $i <= 60; $i++) {
            $order[$i] = "⇑　" . sprintf("%02d", $i) . '　↵';
        }
        return $order;
    }

    /**
     * 获取和当前 Node 平级的节点，只返回和当前 Node 同属于一类的节点数据
     * @param <integer> $current_node_id
     * @return mixed
     */
    public static function getCurrentLevelNodes($current_node_id = 0) {
        if (intval($current_node_id) === 0) {
            $current_node_id = Yii::app()->request->getParam('node');
        }
        $parent = Node::model()->findByPk($current_node_id);
        $criteria = new CDbCriteria();

        $criteria->condition = ($parent !== null)
            ? "parent_id = {$parent->parent_id} AND type = '{$parent->type}'"
            : 'parent_id != 0';
        return Node::model()->findAll($criteria);
    }

    private $_ids;
    public function getIds($parent_id = 1, $include_self = true, $include_subs = true) {
        if ($include_self) $this->_ids[] = $parent_id;
        $criteria = new CDbCriteria();
        $criteria->condition = "parent_id = {$parent_id}";
        $criteria->select = array('id');
        $criteria->order = 'order_pos ASC';
        $nodes = Node::model()->findAll($criteria);
        foreach ($nodes as $node) {
            $node_id = $node->id;
            if ($include_subs) {
                if ($this->hasChild($node_id)) {
                    $this->_ids[] = $node_id;
                    $this->getIds($node_id);
                } else {
                    $this->_ids[] = $node_id;
                }
            } else {
                $this->_ids[] = $node_id;
            }
        }
        return (count($this->_ids) > 2)
            ? array_unique($this->_ids) : $this->_ids;
    }

    // 获取构造 CMenu 所需数据
    public function getCMenuItemsData($parent_id = 1) {
        $items = $this->generateCMenuItemsData($parent_id);
        return (count($items) && $items != null)
            ? YArrayExt::toTree($items, 'id', 'parent', 'items', $refs)
            : $items;
    }

    // 生成 CMenu 所需数据
    private $_CMenu_items_data = null;
    protected function generateCMenuItemsData($parent_id = 1) {
        $criteria = new CDbCriteria();
        $criteria->condition = "parent_id = {$parent_id} AND show_in_menus = 1";
        $criteria->select = array('id', 'name', 'parent_id', 'url_args_frontend');
        $criteria->order = 'order_pos ASC';
        $items = Node::model()->findAll($criteria);
        foreach ($items as $item) {
            $id = $item->id;
            $url_args_frontend = explode('/', $item->url_args_frontend);
            $url = (in_array('node', $url_args_frontend))
                ? array($item->url_args_frontend)
                : array($item->url_args_frontend, 'node' => $item->id);

            $this->_CMenu_items_data[] = array(
                'id' => $id,
                'label' => CHtml::encode($item->name),
                'url' => $url,
                'parent' => $item->parent_id,
            );
            if (self::hasChild($id)) {
                $this->getCMenuItemsData($id);
            }
        }

        return $this->_CMenu_items_data;
    }

    /**
     * 返回 CTreeView 所需数据
     * @param <integer> $parent_id 父节点值
     * @param string $url 生成的树形 URL 链接地址
     * @param string $node_name 节点参数名称，默认为 node，比如你可以修改为 category
     * @param string $root_is_link 父节点是否为链接形式
     * @return <string>
     */
    public function getCTreeViewDatas($parent_id = 1, $url = '', $node_name = 'node', $root_is_link = true, $expanded = false) {
        $datas = $this->generateCTreeViewDatas($parent_id, $url, $node_name, $root_is_link);
        return (count($datas) && $datas != null)
            ? YArrayExt::toTree($datas, 'id', 'parent', 'children', $refs)
            : $datas;
    }

    /**
     * 遍历节点属于 $parent_id 的所有子节点，供 getCTreeViewDatas 生成返回
     * CTreeView 所需数据
     * @var array
     */
    private $_CTreeView_datas;
    public function generateCTreeViewDatas($parent_id = 1, $url = '',
        $node_name = 'node', $root_is_link = true, $expanded = false) {
        $criteria = new CDbCriteria;
        $criteria->condition = 'parent_id = ' . $parent_id;
        $criteria->order = 'order_pos ASC';
        $nodes = Node::model()->findAll($criteria);
        $node_name = (trim($node_name) == '') ? 'node' : trim($node_name);
        foreach ($nodes as $j => $node) {
            $node_id = $node->id;
            if ($this->hasChild($node_id)) {
                if ($root_is_link) {
                    $text = CHtml::link($node->name, array($url, $node_name => $node->id));
                } else {
                    $text = "<span>$node->name</span>";
                }
                $this->_CTreeView_datas[$node_id] = array(
                    'id' => $node_id,
                    'text' => $text,
                    'show_in_menus' => $node->show_in_menus,
                    'open_target' => $node->open_target,
                    'order_pos' => $node->order_pos,
                    'expanded' => $expanded,
                    'classes' => 'important',
                    'parent' => $node->parent_id,
                );
                $this->generateCTreeViewDatas($node_id, $url, $node_name, $root_is_link);
            } else {
                $text = (trim($url) == '')
                    ? CHtml::link($node->name, array("{$node->url_args_backend}/index", $node_name => $node->id))
                    : CHtml::link($node->name, array($url, $node_name => $node->id));
                $this->_CTreeView_datas[$node_id] = array(
                    'id' => $node_id,
                    'text' => $text,
                    'show_in_menus' => $node->show_in_menus,
                    'open_target' => $node->open_target,
                    'order_pos' => $node->order_pos,
                    'expanded' => $expanded,
                    'classes' => 'important',
                    'parent' => $node->parent_id,
                );
            }
        }

        return $this->_CTreeView_datas;
    }

    /**
     * 返回 CTreeView 所需数据（供后台节点管理时使用）
     * @param <integer> $parent_id 父节点值
     * @param string $url 生成的树形 URL 链接地址
     * @param string $node_name 节点参数名称，默认为 node，比如你可以修改为 category
     * @param string $root_is_link 父节点是否为链接形式
     * @return <string>
     */
    public function getCTreeViewManageDatas($parent_id = 1, $url = '', $node_name = 'node', $root_is_link = true, $expanded = false) {
        $datas = $this->generateCTreeViewManageDatas($parent_id, $url, $node_name, $root_is_link);
        return (count($datas) && $datas != null)
            ? YArrayExt::toTree($datas, 'id', 'parent', 'children', $refs)
            : $datas;
    }

    /**
     * 遍历节点属于 $parent_id 的所有子节点，供 getCTreeViewManageDatas 生成返回
     * CTreeView 所需数据（节点管理时使用）
     * @var array
     */
    private $_CTreeView_manage_datas;
    public function generateCTreeViewManageDatas($parent_id = 1, $url = '',
        $node_name = 'node', $root_is_link = true, $expanded = false) {
        $criteria = new CDbCriteria;
        $criteria->condition = 'parent_id = ' . $parent_id;
        $criteria->order = 'order_pos ASC';
        $nodes = Node::model()->findAll($criteria);
        $node_name = (trim($node_name) == '') ? 'node' : trim($node_name);
        foreach ($nodes as $j => $node) {
            $show_in_menu = ($node->show_in_menus) ? "*" : '';
            $node_id = $node->id;
            $type = ucfirst($node->type);
            if ($this->hasChild($node_id)) {
                if ($root_is_link) {
                    $text = CHtml::link("<span>{$show_in_menu}</span><span>{$node->name}</span><span class=\"order_pos\">{$node->order_pos}</span><span>#{$node->id}</span><span class=\"type\">{$type}</span>", array($url, $node_name => $node->id));
                } else {
                    $text = "<span>$node->name</span>";
                }
                $this->_CTreeView_manage_datas[$node_id] = array(
                    'id' => $node_id,
                    'text' => $text,
                    'show_in_menus' => $node->show_in_menus,
                    'open_target' => $node->open_target,
                    'order_pos' => $node->order_pos,
                    'expanded' => $expanded,
                    'classes' => 'important',
                    'parent' => $node->parent_id,
                );
                $this->generateCTreeViewManageDatas($node_id, $url, $node_name, $root_is_link);
            } else {
                $text = (trim($url) == '')
                    ? CHtml::link($node->name, array("{$node->url_args_backend}/index", $node_name => $node->id))
                    : CHtml::link("<span>{$show_in_menu}</span><span>{$node->name}</span><span class=\"order_pos\">{$node->order_pos}</span><span>#{$node->id}</span><span class=\"type\">{$type}</span>", array($url, $node_name => $node->id));
                $this->_CTreeView_manage_datas[$node_id] = array(
                    'id' => $node_id,
                    'text' => $text,
                    'show_in_menus' => $node->show_in_menus,
                    'open_target' => $node->open_target,
                    'order_pos' => $node->order_pos,
                    'expanded' => $expanded,
                    'classes' => 'important',
                    'parent' => $node->parent_id,
                );
            }
        }

        return $this->_CTreeView_manage_datas;
    }

    /**
     * 判断是否有子节点
     * @param integer $node_id
     * @return boolean
     */
    public static function hasChild($node_id) {
        $criteria = new CDbCriteria(array(
            'condition' => "parent_id = {$node_id}",
            'select' => 'id'
        ));
//        $criteria->condition = "parent_id = {$node_id}";
        return (Node::model()->count($criteria)) ? true : false;
    }

    // 根据主键获取节点名称
    public static function getNodeNameByPk($pk) {
        $node = Node::model()->findByPk($pk);
//        $node = Node::model()->find(array(
//            'condition' => "id = {$pk}",
//            'select' => 'name',
//            'limit' => 1
//        ));
        return ($node !== null) ? $node->name : 'Error';
    }

    /**
     * 获取节点信息，作为导航使用
     * 如果当前为一级节点，则只返回当前节点信息，如果上面还有父级节点，则返回父
     * 级节点和本节点的所有信息。
     * @param <integer> $parent
     * @return array with node infos
     */
    public static function getNodeInfos($parent, $include_self = true) {
        $result = self::model()->getParentNodeInfos($parent);
        self::model()->_node_infos = array();
        return $result;
    }

    private $_node_infos = array();
    private function getParentNodeInfos($parent) {
        $current_node = Node::model()->findByPk($parent);
        if ($current_node === null) return self::model()->_node_infos;
        if (!key_exists($current_node->id, self::model()->_node_infos)) {
            self::model()->_node_infos[$current_node->id] = array(
                'id' => $current_node->id,
                'name' => $current_node->name,
                'url_args_frontend' => $current_node->url_args_frontend
            );
        }
        if ($current_node->parent_id != 1) {
            $this->getParentNodeInfos($current_node->parent_id);
        }

        return self::model()->_node_infos;
    }


    public static function getChilds($root_node) {
        if ($root_node === null) return null;
        $datas = self::generateChilds($root_node);
        return (count($datas) && $datas != null)
            ? YArrayExt::toTree($datas, 'id', 'parent', 'children', $refs)
            : $datas;
    }
    // 获取指定根节点的所有子节点
    private $_childs = array();
    public static function generateChilds($root_node) {
        $childs = self::model()->findAll("parent_id = $root_node");
        if (!empty($childs)) {
            foreach ($childs as $child) {
                $url = trim($child->url_args_frontend);
//                if (empty($url)) {
//
//                }
                self::model()->_childs[$child->id] = array(
                    'id' => $child->id,
                    'text' => $child->name,
                    'url_args_frontend' => $child->url_args_frontend,
                    'parent' => $child->parent_id,
                    'hasChildren' => false,
                );
                if (Node::hasChild($child->id)) {
                    self::model()->_childs[$child->id]['hasChildren'] = true;
                    self::getChilds($child->id);
                }
            }
        }

        return self::model()->_childs;
    }

    // 获取指定节点的顶级根节点
    public static function getNodeRootParent($node = null) {
        if ($node === null) return null;
        $result = 0;
        $node_id = self::getNodeParent($node);
        if ($node_id !== null) {
            if (intval($node_id) == 1) {
                $result = $node;
            } else {
                $result = self::getNodeRootParent($node_id);
            }
        } else {
            $result = $node;
        }
        return $result;
    }

    // 获取指定节点的父节点
    public static function getNodeParent($node = null) {
        if ($node === null) return null;
        $criteria = new CDbCriteria();
        $criteria->condition = "id = $node";
        $criteria->select = 'parent_id';
        $node = self::model()->find($criteria);
        return ($node !== null) ? $node->parent_id : null;
    }


    // 根据用户选择的模块写入后台控制器名称
    protected function beforeValidate() {
        switch (trim($this->type)) {
            case self::TYPE_ALBUM:
                $url_args_backend = 'albums';
                break;
            case self::TYPE_ARTICLE;
                $url_args_backend = 'articles';
                break;
            case self::TYPE_BOOK:
                $url_args_backend = 'books';
                break;
            case self::TYPE_DOWNLOAD:
                $url_args_backend = 'downloads';
                break;
            case self::TYPE_FEEDBACK:
                $url_args_backend = 'feedbacks';
                break;
            case self::TYPE_LINK:
                $url_args_backend = 'links';
                break;
            case self::TYPE_MUSIC:
                $url_args_backend = 'music';
                break;
            case self::TYPE_PERSONNEL:
                $url_args_backend = 'personnels';
                break;
            case self::TYPE_POST:
                $url_args_backend = 'posts';
                break;
            case self::TYPE_PRODUCT:
                $url_args_backend = 'products';
                break;
            case self::TYPE_SLIDE:
                $url_args_backend = 'slide';
                break;
            case self::TYPE_USER_CASE:
                $url_args_backend = 'cases';
                break;
            case self::TYPE_VIDEO:
                $url_args_backend = 'videos';
                break;
            case self::TYPE_TODAY_ON_HISTORY:
                $url_args_backend = 'todayOnHistories';
                break;
            case self::TYPE_JOB:
                $url_args_backend = 'jobs';
                break;
            default:
                $url_args_backend = 'unknown';
                break;
        }
        $this->url_args_backend = $url_args_backend;
        return true;
    }

    private $_original_type;
    protected function afterFind() {
        $this->_original_type = $this->type;
    }

    /**
     * 　　如果修改后的节点类型与原始节点类型不一致，将删除属于原始节点内容的所有
     * 已录入的数据。
     * 　　比如原始类型为“友情链接”类型，并且已经添加 10 条友情链接信息，我们将
     * 其修改为“文章”类型，在修改成功之后，将同时删除已经录入的 10 条友情链接数据。
     */
    protected function afterSave() {
        if ((trim($this->_original_type != '')) && (trim($this->_original_type) != trim($this->type))) {
            $criteria = new CDbCriteria;
            $criteria->condition = "node_id = {$this->id}";
            $type = trim($this->_original_type);
            if (isset($type, $this->typeOptions)) {
                $models = CActiveRecord::model($type)->findAll($criteria);
                foreach ($models as $model) {
                    $model->delete();
                }
            } else {
                throw new CHttpException(400, Yii::t('common', 'invalid_request'));
            }
        }
    }

    /*
     * 节点删除之后清除与对应节点的所有关联数据
     */
    protected function afterDelete() {
        $criteria = new CDbCriteria;
        $criteria->condition = "node_id = {$this->id}";
        $type = trim($this->type);
        if (isset($type, $this->typeOptions)) {
            $models = CActiveRecord::model($type)->findAll($criteria);
            foreach ($models as $model) {
                $model->delete();
            }
        } else {
            throw new CHttpException(400, Yii::t('common', 'invalid_request'));
        }
    }
}